1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package java.io;
27
28 import java.io.ObjectStreamClass.WeakClassKey;
29 import java.lang.ref.ReferenceQueue;
30 import java.security.AccessController;
31 import java.security.PrivilegedAction;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 import java.util.concurrent.ConcurrentHashMap;
36 import java.util.concurrent.ConcurrentMap;
37 import static java.io.ObjectStreamClass.processQueue;
38 import java.io.SerialCallbackContext;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 public class ObjectOutputStream
162 extends OutputStream implements ObjectOutput, ObjectStreamConstants
163 {
164
165 private static class Caches {
166
167 static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
168 new ConcurrentHashMap<>();
169
170
171 static final ReferenceQueue<Class<?>> subclassAuditsQueue =
172 new ReferenceQueue<>();
173 }
174
175
176 private final BlockDataOutputStream bout;
177
178 private final HandleTable handles;
179
180 private final ReplaceTable subs;
181
182 private int protocol = PROTOCOL_VERSION_2;
183
184 private int depth;
185
186
187 private byte[] primVals;
188
189
190 private final boolean enableOverride;
191
192 private boolean enableReplace;
193
194
195
196
197
198
199
200 private SerialCallbackContext curContext;
201
202 private PutFieldImpl curPut;
203
204
205 private final DebugTraceInfoStack debugInfoStack;
206
207
208
209
210
211 private static final boolean extendedDebugInfo =
212 java.security.AccessController.doPrivileged(
213 new sun.security.action.GetBooleanAction(
214 "sun.io.serialization.extendedDebugInfo")).booleanValue();
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239 public ObjectOutputStream(OutputStream out) throws IOException {
240 verifySubclass();
241 bout = new BlockDataOutputStream(out);
242 handles = new HandleTable(10, (float) 3.00);
243 subs = new ReplaceTable(10, (float) 3.00);
244 enableOverride = false;
245 writeStreamHeader();
246 bout.setBlockDataMode(true);
247 if (extendedDebugInfo) {
248 debugInfoStack = new DebugTraceInfoStack();
249 } else {
250 debugInfoStack = null;
251 }
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 protected ObjectOutputStream() throws IOException, SecurityException {
271 SecurityManager sm = System.getSecurityManager();
272 if (sm != null) {
273 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
274 }
275 bout = null;
276 handles = null;
277 subs = null;
278 enableOverride = true;
279 debugInfoStack = null;
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302 public void useProtocolVersion(int version) throws IOException {
303 if (handles.size() != 0) {
304
305 throw new IllegalStateException("stream non-empty");
306 }
307 switch (version) {
308 case PROTOCOL_VERSION_1:
309 case PROTOCOL_VERSION_2:
310 protocol = version;
311 break;
312
313 default:
314 throw new IllegalArgumentException(
315 "unknown version: " + version);
316 }
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 public final void writeObject(Object obj) throws IOException {
341 if (enableOverride) {
342 writeObjectOverride(obj);
343 return;
344 }
345 try {
346 writeObject0(obj, false);
347 } catch (IOException ex) {
348 if (depth == 0) {
349 writeFatalException(ex);
350 }
351 throw ex;
352 }
353 }
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 protected void writeObjectOverride(Object obj) throws IOException {
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411 public void writeUnshared(Object obj) throws IOException {
412 try {
413 writeObject0(obj, true);
414 } catch (IOException ex) {
415 if (depth == 0) {
416 writeFatalException(ex);
417 }
418 throw ex;
419 }
420 }
421
422
423
424
425
426
427
428
429
430
431 public void defaultWriteObject() throws IOException {
432 if ( curContext == null ) {
433 throw new NotActiveException("not in call to writeObject");
434 }
435 Object curObj = curContext.getObj();
436 ObjectStreamClass curDesc = curContext.getDesc();
437 bout.setBlockDataMode(false);
438 defaultWriteFields(curObj, curDesc);
439 bout.setBlockDataMode(true);
440 }
441
442
443
444
445
446
447
448
449
450
451
452 public ObjectOutputStream.PutField putFields() throws IOException {
453 if (curPut == null) {
454 if (curContext == null) {
455 throw new NotActiveException("not in call to writeObject");
456 }
457 Object curObj = curContext.getObj();
458 ObjectStreamClass curDesc = curContext.getDesc();
459 curPut = new PutFieldImpl(curDesc);
460 }
461 return curPut;
462 }
463
464
465
466
467
468
469
470
471
472
473 public void writeFields() throws IOException {
474 if (curPut == null) {
475 throw new NotActiveException("no current PutField object");
476 }
477 bout.setBlockDataMode(false);
478 curPut.writeFields();
479 bout.setBlockDataMode(true);
480 }
481
482
483
484
485
486
487
488
489
490
491
492 public void reset() throws IOException {
493 if (depth != 0) {
494 throw new IOException("stream active");
495 }
496 bout.setBlockDataMode(false);
497 bout.writeByte(TC_RESET);
498 clear();
499 bout.setBlockDataMode(true);
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518 protected void annotateClass(Class<?> cl) throws IOException {
519 }
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 protected void annotateProxyClass(Class<?> cl) throws IOException {
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583 protected Object replaceObject(Object obj) throws IOException {
584 return obj;
585 }
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607 protected boolean enableReplaceObject(boolean enable)
608 throws SecurityException
609 {
610 if (enable == enableReplace) {
611 return enable;
612 }
613 if (enable) {
614 SecurityManager sm = System.getSecurityManager();
615 if (sm != null) {
616 sm.checkPermission(SUBSTITUTION_PERMISSION);
617 }
618 }
619 enableReplace = enable;
620 return !enableReplace;
621 }
622
623
624
625
626
627
628
629
630
631 protected void writeStreamHeader() throws IOException {
632 bout.writeShort(STREAM_MAGIC);
633 bout.writeShort(STREAM_VERSION);
634 }
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661 protected void writeClassDescriptor(ObjectStreamClass desc)
662 throws IOException
663 {
664 desc.writeNonProxy(this);
665 }
666
667
668
669
670
671
672
673
674 public void write(int val) throws IOException {
675 bout.write(val);
676 }
677
678
679
680
681
682
683
684
685 public void write(byte[] buf) throws IOException {
686 bout.write(buf, 0, buf.length, false);
687 }
688
689
690
691
692
693
694
695
696
697 public void write(byte[] buf, int off, int len) throws IOException {
698 if (buf == null) {
699 throw new NullPointerException();
700 }
701 int endoff = off + len;
702 if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
703 throw new IndexOutOfBoundsException();
704 }
705 bout.write(buf, off, len, false);
706 }
707
708
709
710
711
712
713
714 public void flush() throws IOException {
715 bout.flush();
716 }
717
718
719
720
721
722
723
724
725 protected void drain() throws IOException {
726 bout.drain();
727 }
728
729
730
731
732
733
734
735 public void close() throws IOException {
736 flush();
737 clear();
738 bout.close();
739 }
740
741
742
743
744
745
746
747
748 public void writeBoolean(boolean val) throws IOException {
749 bout.writeBoolean(val);
750 }
751
752
753
754
755
756
757
758
759 public void writeByte(int val) throws IOException {
760 bout.writeByte(val);
761 }
762
763
764
765
766
767
768
769
770 public void writeShort(int val) throws IOException {
771 bout.writeShort(val);
772 }
773
774
775
776
777
778
779
780
781 public void writeChar(int val) throws IOException {
782 bout.writeChar(val);
783 }
784
785
786
787
788
789
790
791
792 public void writeInt(int val) throws IOException {
793 bout.writeInt(val);
794 }
795
796
797
798
799
800
801
802
803 public void writeLong(long val) throws IOException {
804 bout.writeLong(val);
805 }
806
807
808
809
810
811
812
813
814 public void writeFloat(float val) throws IOException {
815 bout.writeFloat(val);
816 }
817
818
819
820
821
822
823
824
825 public void writeDouble(double val) throws IOException {
826 bout.writeDouble(val);
827 }
828
829
830
831
832
833
834
835
836 public void writeBytes(String str) throws IOException {
837 bout.writeBytes(str);
838 }
839
840
841
842
843
844
845
846
847 public void writeChars(String str) throws IOException {
848 bout.writeChars(str);
849 }
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864 public void writeUTF(String str) throws IOException {
865 bout.writeUTF(str);
866 }
867
868
869
870
871
872
873
874 public static abstract class PutField {
875
876
877
878
879
880
881
882
883
884
885
886 public abstract void put(String name, boolean val);
887
888
889
890
891
892
893
894
895
896
897
898 public abstract void put(String name, byte val);
899
900
901
902
903
904
905
906
907
908
909
910 public abstract void put(String name, char val);
911
912
913
914
915
916
917
918
919
920
921
922 public abstract void put(String name, short val);
923
924
925
926
927
928
929
930
931
932
933
934 public abstract void put(String name, int val);
935
936
937
938
939
940
941
942
943
944
945
946 public abstract void put(String name, long val);
947
948
949
950
951
952
953
954
955
956
957
958 public abstract void put(String name, float val);
959
960
961
962
963
964
965
966
967
968
969
970 public abstract void put(String name, double val);
971
972
973
974
975
976
977
978
979
980
981
982
983 public abstract void put(String name, Object val);
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003 @Deprecated
1004 public abstract void write(ObjectOutput out) throws IOException;
1005 }
1006
1007
1008
1009
1010
1011 int getProtocolVersion() {
1012 return protocol;
1013 }
1014
1015
1016
1017
1018
1019 void writeTypeString(String str) throws IOException {
1020 int handle;
1021 if (str == null) {
1022 writeNull();
1023 } else if ((handle = handles.lookup(str)) != -1) {
1024 writeHandle(handle);
1025 } else {
1026 writeString(str, false);
1027 }
1028 }
1029
1030
1031
1032
1033
1034
1035
1036 private void verifySubclass() {
1037 Class cl = getClass();
1038 if (cl == ObjectOutputStream.class) {
1039 return;
1040 }
1041 SecurityManager sm = System.getSecurityManager();
1042 if (sm == null) {
1043 return;
1044 }
1045 processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
1046 WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
1047 Boolean result = Caches.subclassAudits.get(key);
1048 if (result == null) {
1049 result = Boolean.valueOf(auditSubclass(cl));
1050 Caches.subclassAudits.putIfAbsent(key, result);
1051 }
1052 if (result.booleanValue()) {
1053 return;
1054 }
1055 sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
1056 }
1057
1058
1059
1060
1061
1062
1063 private static boolean auditSubclass(final Class subcl) {
1064 Boolean result = AccessController.doPrivileged(
1065 new PrivilegedAction<Boolean>() {
1066 public Boolean run() {
1067 for (Class cl = subcl;
1068 cl != ObjectOutputStream.class;
1069 cl = cl.getSuperclass())
1070 {
1071 try {
1072 cl.getDeclaredMethod(
1073 "writeUnshared", new Class[] { Object.class });
1074 return Boolean.FALSE;
1075 } catch (NoSuchMethodException ex) {
1076 }
1077 try {
1078 cl.getDeclaredMethod("putFields", (Class[]) null);
1079 return Boolean.FALSE;
1080 } catch (NoSuchMethodException ex) {
1081 }
1082 }
1083 return Boolean.TRUE;
1084 }
1085 }
1086 );
1087 return result.booleanValue();
1088 }
1089
1090
1091
1092
1093 private void clear() {
1094 subs.clear();
1095 handles.clear();
1096 }
1097
1098
1099
1100
1101 private void writeObject0(Object obj, boolean unshared)
1102 throws IOException
1103 {
1104 boolean oldMode = bout.setBlockDataMode(false);
1105 depth++;
1106 try {
1107
1108 int h;
1109 if ((obj = subs.lookup(obj)) == null) {
1110 writeNull();
1111 return;
1112 } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1113 writeHandle(h);
1114 return;
1115 } else if (obj instanceof Class) {
1116 writeClass((Class) obj, unshared);
1117 return;
1118 } else if (obj instanceof ObjectStreamClass) {
1119 writeClassDesc((ObjectStreamClass) obj, unshared);
1120 return;
1121 }
1122
1123
1124 Object orig = obj;
1125 Class cl = obj.getClass();
1126 ObjectStreamClass desc;
1127 for (;;) {
1128
1129 Class repCl;
1130 desc = ObjectStreamClass.lookup(cl, true);
1131 if (!desc.hasWriteReplaceMethod() ||
1132 (obj = desc.invokeWriteReplace(obj)) == null ||
1133 (repCl = obj.getClass()) == cl)
1134 {
1135 break;
1136 }
1137 cl = repCl;
1138 }
1139 if (enableReplace) {
1140 Object rep = replaceObject(obj);
1141 if (rep != obj && rep != null) {
1142 cl = rep.getClass();
1143 desc = ObjectStreamClass.lookup(cl, true);
1144 }
1145 obj = rep;
1146 }
1147
1148
1149 if (obj != orig) {
1150 subs.assign(orig, obj);
1151 if (obj == null) {
1152 writeNull();
1153 return;
1154 } else if (!unshared && (h = handles.lookup(obj)) != -1) {
1155 writeHandle(h);
1156 return;
1157 } else if (obj instanceof Class) {
1158 writeClass((Class) obj, unshared);
1159 return;
1160 } else if (obj instanceof ObjectStreamClass) {
1161 writeClassDesc((ObjectStreamClass) obj, unshared);
1162 return;
1163 }
1164 }
1165
1166
1167 if (obj instanceof String) {
1168 writeString((String) obj, unshared);
1169 } else if (cl.isArray()) {
1170 writeArray(obj, desc, unshared);
1171 } else if (obj instanceof Enum) {
1172 writeEnum((Enum) obj, desc, unshared);
1173 } else if (obj instanceof Serializable) {
1174 writeOrdinaryObject(obj, desc, unshared);
1175 } else {
1176 if (extendedDebugInfo) {
1177 throw new NotSerializableException(
1178 cl.getName() + "\n" + debugInfoStack.toString());
1179 } else {
1180 throw new NotSerializableException(cl.getName());
1181 }
1182 }
1183 } finally {
1184 depth--;
1185 bout.setBlockDataMode(oldMode);
1186 }
1187 }
1188
1189
1190
1191
1192 private void writeNull() throws IOException {
1193 bout.writeByte(TC_NULL);
1194 }
1195
1196
1197
1198
1199 private void writeHandle(int handle) throws IOException {
1200 bout.writeByte(TC_REFERENCE);
1201 bout.writeInt(baseWireHandle + handle);
1202 }
1203
1204
1205
1206
1207 private void writeClass(Class cl, boolean unshared) throws IOException {
1208 bout.writeByte(TC_CLASS);
1209 writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
1210 handles.assign(unshared ? null : cl);
1211 }
1212
1213
1214
1215
1216 private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
1217 throws IOException
1218 {
1219 int handle;
1220 if (desc == null) {
1221 writeNull();
1222 } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
1223 writeHandle(handle);
1224 } else if (desc.isProxy()) {
1225 writeProxyDesc(desc, unshared);
1226 } else {
1227 writeNonProxyDesc(desc, unshared);
1228 }
1229 }
1230
1231
1232
1233
1234 private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
1235 throws IOException
1236 {
1237 bout.writeByte(TC_PROXYCLASSDESC);
1238 handles.assign(unshared ? null : desc);
1239
1240 Class cl = desc.forClass();
1241 Class[] ifaces = cl.getInterfaces();
1242 bout.writeInt(ifaces.length);
1243 for (int i = 0; i < ifaces.length; i++) {
1244 bout.writeUTF(ifaces[i].getName());
1245 }
1246
1247 bout.setBlockDataMode(true);
1248 annotateProxyClass(cl);
1249 bout.setBlockDataMode(false);
1250 bout.writeByte(TC_ENDBLOCKDATA);
1251
1252 writeClassDesc(desc.getSuperDesc(), false);
1253 }
1254
1255
1256
1257
1258
1259 private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
1260 throws IOException
1261 {
1262 bout.writeByte(TC_CLASSDESC);
1263 handles.assign(unshared ? null : desc);
1264
1265 if (protocol == PROTOCOL_VERSION_1) {
1266
1267 desc.writeNonProxy(this);
1268 } else {
1269 writeClassDescriptor(desc);
1270 }
1271
1272 Class cl = desc.forClass();
1273 bout.setBlockDataMode(true);
1274 annotateClass(cl);
1275 bout.setBlockDataMode(false);
1276 bout.writeByte(TC_ENDBLOCKDATA);
1277
1278 writeClassDesc(desc.getSuperDesc(), false);
1279 }
1280
1281
1282
1283
1284
1285 private void writeString(String str, boolean unshared) throws IOException {
1286 handles.assign(unshared ? null : str);
1287 long utflen = bout.getUTFLength(str);
1288 if (utflen <= 0xFFFF) {
1289 bout.writeByte(TC_STRING);
1290 bout.writeUTF(str, utflen);
1291 } else {
1292 bout.writeByte(TC_LONGSTRING);
1293 bout.writeLongUTF(str, utflen);
1294 }
1295 }
1296
1297
1298
1299
1300 private void writeArray(Object array,
1301 ObjectStreamClass desc,
1302 boolean unshared)
1303 throws IOException
1304 {
1305 bout.writeByte(TC_ARRAY);
1306 writeClassDesc(desc, false);
1307 handles.assign(unshared ? null : array);
1308
1309 Class ccl = desc.forClass().getComponentType();
1310 if (ccl.isPrimitive()) {
1311 if (ccl == Integer.TYPE) {
1312 int[] ia = (int[]) array;
1313 bout.writeInt(ia.length);
1314 bout.writeInts(ia, 0, ia.length);
1315 } else if (ccl == Byte.TYPE) {
1316 byte[] ba = (byte[]) array;
1317 bout.writeInt(ba.length);
1318 bout.write(ba, 0, ba.length, true);
1319 } else if (ccl == Long.TYPE) {
1320 long[] ja = (long[]) array;
1321 bout.writeInt(ja.length);
1322 bout.writeLongs(ja, 0, ja.length);
1323 } else if (ccl == Float.TYPE) {
1324 float[] fa = (float[]) array;
1325 bout.writeInt(fa.length);
1326 bout.writeFloats(fa, 0, fa.length);
1327 } else if (ccl == Double.TYPE) {
1328 double[] da = (double[]) array;
1329 bout.writeInt(da.length);
1330 bout.writeDoubles(da, 0, da.length);
1331 } else if (ccl == Short.TYPE) {
1332 short[] sa = (short[]) array;
1333 bout.writeInt(sa.length);
1334 bout.writeShorts(sa, 0, sa.length);
1335 } else if (ccl == Character.TYPE) {
1336 char[] ca = (char[]) array;
1337 bout.writeInt(ca.length);
1338 bout.writeChars(ca, 0, ca.length);
1339 } else if (ccl == Boolean.TYPE) {
1340 boolean[] za = (boolean[]) array;
1341 bout.writeInt(za.length);
1342 bout.writeBooleans(za, 0, za.length);
1343 } else {
1344 throw new InternalError();
1345 }
1346 } else {
1347 Object[] objs = (Object[]) array;
1348 int len = objs.length;
1349 bout.writeInt(len);
1350 if (extendedDebugInfo) {
1351 debugInfoStack.push(
1352 "array (class \"" + array.getClass().getName() +
1353 "\", size: " + len + ")");
1354 }
1355 try {
1356 for (int i = 0; i < len; i++) {
1357 if (extendedDebugInfo) {
1358 debugInfoStack.push(
1359 "element of array (index: " + i + ")");
1360 }
1361 try {
1362 writeObject0(objs[i], false);
1363 } finally {
1364 if (extendedDebugInfo) {
1365 debugInfoStack.pop();
1366 }
1367 }
1368 }
1369 } finally {
1370 if (extendedDebugInfo) {
1371 debugInfoStack.pop();
1372 }
1373 }
1374 }
1375 }
1376
1377
1378
1379
1380 private void writeEnum(Enum en,
1381 ObjectStreamClass desc,
1382 boolean unshared)
1383 throws IOException
1384 {
1385 bout.writeByte(TC_ENUM);
1386 ObjectStreamClass sdesc = desc.getSuperDesc();
1387 writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
1388 handles.assign(unshared ? null : en);
1389 writeString(en.name(), false);
1390 }
1391
1392
1393
1394
1395
1396
1397 private void writeOrdinaryObject(Object obj,
1398 ObjectStreamClass desc,
1399 boolean unshared)
1400 throws IOException
1401 {
1402 if (extendedDebugInfo) {
1403 debugInfoStack.push(
1404 (depth == 1 ? "root " : "") + "object (class \"" +
1405 obj.getClass().getName() + "\", " + obj.toString() + ")");
1406 }
1407 try {
1408 desc.checkSerialize();
1409
1410 bout.writeByte(TC_OBJECT);
1411 writeClassDesc(desc, false);
1412 handles.assign(unshared ? null : obj);
1413 if (desc.isExternalizable() && !desc.isProxy()) {
1414 writeExternalData((Externalizable) obj);
1415 } else {
1416 writeSerialData(obj, desc);
1417 }
1418 } finally {
1419 if (extendedDebugInfo) {
1420 debugInfoStack.pop();
1421 }
1422 }
1423 }
1424
1425
1426
1427
1428
1429 private void writeExternalData(Externalizable obj) throws IOException {
1430 PutFieldImpl oldPut = curPut;
1431 curPut = null;
1432
1433 if (extendedDebugInfo) {
1434 debugInfoStack.push("writeExternal data");
1435 }
1436 SerialCallbackContext oldContext = curContext;
1437 try {
1438 curContext = null;
1439 if (protocol == PROTOCOL_VERSION_1) {
1440 obj.writeExternal(this);
1441 } else {
1442 bout.setBlockDataMode(true);
1443 obj.writeExternal(this);
1444 bout.setBlockDataMode(false);
1445 bout.writeByte(TC_ENDBLOCKDATA);
1446 }
1447 } finally {
1448 curContext = oldContext;
1449 if (extendedDebugInfo) {
1450 debugInfoStack.pop();
1451 }
1452 }
1453
1454 curPut = oldPut;
1455 }
1456
1457
1458
1459
1460
1461 private void writeSerialData(Object obj, ObjectStreamClass desc)
1462 throws IOException
1463 {
1464 ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
1465 for (int i = 0; i < slots.length; i++) {
1466 ObjectStreamClass slotDesc = slots[i].desc;
1467 if (slotDesc.hasWriteObjectMethod()) {
1468 PutFieldImpl oldPut = curPut;
1469 curPut = null;
1470 SerialCallbackContext oldContext = curContext;
1471
1472 if (extendedDebugInfo) {
1473 debugInfoStack.push(
1474 "custom writeObject data (class \"" +
1475 slotDesc.getName() + "\")");
1476 }
1477 try {
1478 curContext = new SerialCallbackContext(obj, slotDesc);
1479 bout.setBlockDataMode(true);
1480 slotDesc.invokeWriteObject(obj, this);
1481 bout.setBlockDataMode(false);
1482 bout.writeByte(TC_ENDBLOCKDATA);
1483 } finally {
1484 curContext.setUsed();
1485 curContext = oldContext;
1486 if (extendedDebugInfo) {
1487 debugInfoStack.pop();
1488 }
1489 }
1490
1491 curPut = oldPut;
1492 } else {
1493 defaultWriteFields(obj, slotDesc);
1494 }
1495 }
1496 }
1497
1498
1499
1500
1501
1502
1503 private void defaultWriteFields(Object obj, ObjectStreamClass desc)
1504 throws IOException
1505 {
1506
1507 desc.checkDefaultSerialize();
1508
1509 int primDataSize = desc.getPrimDataSize();
1510 if (primVals == null || primVals.length < primDataSize) {
1511 primVals = new byte[primDataSize];
1512 }
1513 desc.getPrimFieldValues(obj, primVals);
1514 bout.write(primVals, 0, primDataSize, false);
1515
1516 ObjectStreamField[] fields = desc.getFields(false);
1517 Object[] objVals = new Object[desc.getNumObjFields()];
1518 int numPrimFields = fields.length - objVals.length;
1519 desc.getObjFieldValues(obj, objVals);
1520 for (int i = 0; i < objVals.length; i++) {
1521 if (extendedDebugInfo) {
1522 debugInfoStack.push(
1523 "field (class \"" + desc.getName() + "\", name: \"" +
1524 fields[numPrimFields + i].getName() + "\", type: \"" +
1525 fields[numPrimFields + i].getType() + "\")");
1526 }
1527 try {
1528 writeObject0(objVals[i],
1529 fields[numPrimFields + i].isUnshared());
1530 } finally {
1531 if (extendedDebugInfo) {
1532 debugInfoStack.pop();
1533 }
1534 }
1535 }
1536 }
1537
1538
1539
1540
1541
1542 private void writeFatalException(IOException ex) throws IOException {
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553 clear();
1554 boolean oldMode = bout.setBlockDataMode(false);
1555 try {
1556 bout.writeByte(TC_EXCEPTION);
1557 writeObject0(ex, false);
1558 clear();
1559 } finally {
1560 bout.setBlockDataMode(oldMode);
1561 }
1562 }
1563
1564
1565
1566
1567
1568 private static native void floatsToBytes(float[] src, int srcpos,
1569 byte[] dst, int dstpos,
1570 int nfloats);
1571
1572
1573
1574
1575
1576 private static native void doublesToBytes(double[] src, int srcpos,
1577 byte[] dst, int dstpos,
1578 int ndoubles);
1579
1580
1581
1582
1583 private class PutFieldImpl extends PutField {
1584
1585
1586 private final ObjectStreamClass desc;
1587
1588 private final byte[] primVals;
1589
1590 private final Object[] objVals;
1591
1592
1593
1594
1595
1596 PutFieldImpl(ObjectStreamClass desc) {
1597 this.desc = desc;
1598 primVals = new byte[desc.getPrimDataSize()];
1599 objVals = new Object[desc.getNumObjFields()];
1600 }
1601
1602 public void put(String name, boolean val) {
1603 Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
1604 }
1605
1606 public void put(String name, byte val) {
1607 primVals[getFieldOffset(name, Byte.TYPE)] = val;
1608 }
1609
1610 public void put(String name, char val) {
1611 Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
1612 }
1613
1614 public void put(String name, short val) {
1615 Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
1616 }
1617
1618 public void put(String name, int val) {
1619 Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
1620 }
1621
1622 public void put(String name, float val) {
1623 Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
1624 }
1625
1626 public void put(String name, long val) {
1627 Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
1628 }
1629
1630 public void put(String name, double val) {
1631 Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
1632 }
1633
1634 public void put(String name, Object val) {
1635 objVals[getFieldOffset(name, Object.class)] = val;
1636 }
1637
1638
1639 public void write(ObjectOutput out) throws IOException {
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655 if (ObjectOutputStream.this != out) {
1656 throw new IllegalArgumentException("wrong stream");
1657 }
1658 out.write(primVals, 0, primVals.length);
1659
1660 ObjectStreamField[] fields = desc.getFields(false);
1661 int numPrimFields = fields.length - objVals.length;
1662
1663 for (int i = 0; i < objVals.length; i++) {
1664 if (fields[numPrimFields + i].isUnshared()) {
1665 throw new IOException("cannot write unshared object");
1666 }
1667 out.writeObject(objVals[i]);
1668 }
1669 }
1670
1671
1672
1673
1674 void writeFields() throws IOException {
1675 bout.write(primVals, 0, primVals.length, false);
1676
1677 ObjectStreamField[] fields = desc.getFields(false);
1678 int numPrimFields = fields.length - objVals.length;
1679 for (int i = 0; i < objVals.length; i++) {
1680 if (extendedDebugInfo) {
1681 debugInfoStack.push(
1682 "field (class \"" + desc.getName() + "\", name: \"" +
1683 fields[numPrimFields + i].getName() + "\", type: \"" +
1684 fields[numPrimFields + i].getType() + "\")");
1685 }
1686 try {
1687 writeObject0(objVals[i],
1688 fields[numPrimFields + i].isUnshared());
1689 } finally {
1690 if (extendedDebugInfo) {
1691 debugInfoStack.pop();
1692 }
1693 }
1694 }
1695 }
1696
1697
1698
1699
1700
1701
1702
1703 private int getFieldOffset(String name, Class type) {
1704 ObjectStreamField field = desc.getField(name, type);
1705 if (field == null) {
1706 throw new IllegalArgumentException("no such field " + name +
1707 " with type " + type);
1708 }
1709 return field.getOffset();
1710 }
1711 }
1712
1713
1714
1715
1716
1717
1718
1719 private static class BlockDataOutputStream
1720 extends OutputStream implements DataOutput
1721 {
1722
1723 private static final int MAX_BLOCK_SIZE = 1024;
1724
1725 private static final int MAX_HEADER_SIZE = 5;
1726
1727 private static final int CHAR_BUF_SIZE = 256;
1728
1729
1730 private final byte[] buf = new byte[MAX_BLOCK_SIZE];
1731
1732 private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
1733
1734 private final char[] cbuf = new char[CHAR_BUF_SIZE];
1735
1736
1737 private boolean blkmode = false;
1738
1739 private int pos = 0;
1740
1741
1742 private final OutputStream out;
1743
1744 private final DataOutputStream dout;
1745
1746
1747
1748
1749
1750 BlockDataOutputStream(OutputStream out) {
1751 this.out = out;
1752 dout = new DataOutputStream(this);
1753 }
1754
1755
1756
1757
1758
1759
1760
1761
1762 boolean setBlockDataMode(boolean mode) throws IOException {
1763 if (blkmode == mode) {
1764 return blkmode;
1765 }
1766 drain();
1767 blkmode = mode;
1768 return !blkmode;
1769 }
1770
1771
1772
1773
1774
1775 boolean getBlockDataMode() {
1776 return blkmode;
1777 }
1778
1779
1780
1781
1782
1783
1784
1785
1786 public void write(int b) throws IOException {
1787 if (pos >= MAX_BLOCK_SIZE) {
1788 drain();
1789 }
1790 buf[pos++] = (byte) b;
1791 }
1792
1793 public void write(byte[] b) throws IOException {
1794 write(b, 0, b.length, false);
1795 }
1796
1797 public void write(byte[] b, int off, int len) throws IOException {
1798 write(b, off, len, false);
1799 }
1800
1801 public void flush() throws IOException {
1802 drain();
1803 out.flush();
1804 }
1805
1806 public void close() throws IOException {
1807 flush();
1808 out.close();
1809 }
1810
1811
1812
1813
1814
1815
1816
1817 void write(byte[] b, int off, int len, boolean copy)
1818 throws IOException
1819 {
1820 if (!(copy || blkmode)) {
1821 drain();
1822 out.write(b, off, len);
1823 return;
1824 }
1825
1826 while (len > 0) {
1827 if (pos >= MAX_BLOCK_SIZE) {
1828 drain();
1829 }
1830 if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
1831
1832 writeBlockHeader(MAX_BLOCK_SIZE);
1833 out.write(b, off, MAX_BLOCK_SIZE);
1834 off += MAX_BLOCK_SIZE;
1835 len -= MAX_BLOCK_SIZE;
1836 } else {
1837 int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
1838 System.arraycopy(b, off, buf, pos, wlen);
1839 pos += wlen;
1840 off += wlen;
1841 len -= wlen;
1842 }
1843 }
1844 }
1845
1846
1847
1848
1849
1850 void drain() throws IOException {
1851 if (pos == 0) {
1852 return;
1853 }
1854 if (blkmode) {
1855 writeBlockHeader(pos);
1856 }
1857 out.write(buf, 0, pos);
1858 pos = 0;
1859 }
1860
1861
1862
1863
1864
1865
1866 private void writeBlockHeader(int len) throws IOException {
1867 if (len <= 0xFF) {
1868 hbuf[0] = TC_BLOCKDATA;
1869 hbuf[1] = (byte) len;
1870 out.write(hbuf, 0, 2);
1871 } else {
1872 hbuf[0] = TC_BLOCKDATALONG;
1873 Bits.putInt(hbuf, 1, len);
1874 out.write(hbuf, 0, 5);
1875 }
1876 }
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886 public void writeBoolean(boolean v) throws IOException {
1887 if (pos >= MAX_BLOCK_SIZE) {
1888 drain();
1889 }
1890 Bits.putBoolean(buf, pos++, v);
1891 }
1892
1893 public void writeByte(int v) throws IOException {
1894 if (pos >= MAX_BLOCK_SIZE) {
1895 drain();
1896 }
1897 buf[pos++] = (byte) v;
1898 }
1899
1900 public void writeChar(int v) throws IOException {
1901 if (pos + 2 <= MAX_BLOCK_SIZE) {
1902 Bits.putChar(buf, pos, (char) v);
1903 pos += 2;
1904 } else {
1905 dout.writeChar(v);
1906 }
1907 }
1908
1909 public void writeShort(int v) throws IOException {
1910 if (pos + 2 <= MAX_BLOCK_SIZE) {
1911 Bits.putShort(buf, pos, (short) v);
1912 pos += 2;
1913 } else {
1914 dout.writeShort(v);
1915 }
1916 }
1917
1918 public void writeInt(int v) throws IOException {
1919 if (pos + 4 <= MAX_BLOCK_SIZE) {
1920 Bits.putInt(buf, pos, v);
1921 pos += 4;
1922 } else {
1923 dout.writeInt(v);
1924 }
1925 }
1926
1927 public void writeFloat(float v) throws IOException {
1928 if (pos + 4 <= MAX_BLOCK_SIZE) {
1929 Bits.putFloat(buf, pos, v);
1930 pos += 4;
1931 } else {
1932 dout.writeFloat(v);
1933 }
1934 }
1935
1936 public void writeLong(long v) throws IOException {
1937 if (pos + 8 <= MAX_BLOCK_SIZE) {
1938 Bits.putLong(buf, pos, v);
1939 pos += 8;
1940 } else {
1941 dout.writeLong(v);
1942 }
1943 }
1944
1945 public void writeDouble(double v) throws IOException {
1946 if (pos + 8 <= MAX_BLOCK_SIZE) {
1947 Bits.putDouble(buf, pos, v);
1948 pos += 8;
1949 } else {
1950 dout.writeDouble(v);
1951 }
1952 }
1953
1954 public void writeBytes(String s) throws IOException {
1955 int endoff = s.length();
1956 int cpos = 0;
1957 int csize = 0;
1958 for (int off = 0; off < endoff; ) {
1959 if (cpos >= csize) {
1960 cpos = 0;
1961 csize = Math.min(endoff - off, CHAR_BUF_SIZE);
1962 s.getChars(off, off + csize, cbuf, 0);
1963 }
1964 if (pos >= MAX_BLOCK_SIZE) {
1965 drain();
1966 }
1967 int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
1968 int stop = pos + n;
1969 while (pos < stop) {
1970 buf[pos++] = (byte) cbuf[cpos++];
1971 }
1972 off += n;
1973 }
1974 }
1975
1976 public void writeChars(String s) throws IOException {
1977 int endoff = s.length();
1978 for (int off = 0; off < endoff; ) {
1979 int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
1980 s.getChars(off, off + csize, cbuf, 0);
1981 writeChars(cbuf, 0, csize);
1982 off += csize;
1983 }
1984 }
1985
1986 public void writeUTF(String s) throws IOException {
1987 writeUTF(s, getUTFLength(s));
1988 }
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999 void writeBooleans(boolean[] v, int off, int len) throws IOException {
2000 int endoff = off + len;
2001 while (off < endoff) {
2002 if (pos >= MAX_BLOCK_SIZE) {
2003 drain();
2004 }
2005 int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
2006 while (off < stop) {
2007 Bits.putBoolean(buf, pos++, v[off++]);
2008 }
2009 }
2010 }
2011
2012 void writeChars(char[] v, int off, int len) throws IOException {
2013 int limit = MAX_BLOCK_SIZE - 2;
2014 int endoff = off + len;
2015 while (off < endoff) {
2016 if (pos <= limit) {
2017 int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2018 int stop = Math.min(endoff, off + avail);
2019 while (off < stop) {
2020 Bits.putChar(buf, pos, v[off++]);
2021 pos += 2;
2022 }
2023 } else {
2024 dout.writeChar(v[off++]);
2025 }
2026 }
2027 }
2028
2029 void writeShorts(short[] v, int off, int len) throws IOException {
2030 int limit = MAX_BLOCK_SIZE - 2;
2031 int endoff = off + len;
2032 while (off < endoff) {
2033 if (pos <= limit) {
2034 int avail = (MAX_BLOCK_SIZE - pos) >> 1;
2035 int stop = Math.min(endoff, off + avail);
2036 while (off < stop) {
2037 Bits.putShort(buf, pos, v[off++]);
2038 pos += 2;
2039 }
2040 } else {
2041 dout.writeShort(v[off++]);
2042 }
2043 }
2044 }
2045
2046 void writeInts(int[] v, int off, int len) throws IOException {
2047 int limit = MAX_BLOCK_SIZE - 4;
2048 int endoff = off + len;
2049 while (off < endoff) {
2050 if (pos <= limit) {
2051 int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2052 int stop = Math.min(endoff, off + avail);
2053 while (off < stop) {
2054 Bits.putInt(buf, pos, v[off++]);
2055 pos += 4;
2056 }
2057 } else {
2058 dout.writeInt(v[off++]);
2059 }
2060 }
2061 }
2062
2063 void writeFloats(float[] v, int off, int len) throws IOException {
2064 int limit = MAX_BLOCK_SIZE - 4;
2065 int endoff = off + len;
2066 while (off < endoff) {
2067 if (pos <= limit) {
2068 int avail = (MAX_BLOCK_SIZE - pos) >> 2;
2069 int chunklen = Math.min(endoff - off, avail);
2070 floatsToBytes(v, off, buf, pos, chunklen);
2071 off += chunklen;
2072 pos += chunklen << 2;
2073 } else {
2074 dout.writeFloat(v[off++]);
2075 }
2076 }
2077 }
2078
2079 void writeLongs(long[] v, int off, int len) throws IOException {
2080 int limit = MAX_BLOCK_SIZE - 8;
2081 int endoff = off + len;
2082 while (off < endoff) {
2083 if (pos <= limit) {
2084 int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2085 int stop = Math.min(endoff, off + avail);
2086 while (off < stop) {
2087 Bits.putLong(buf, pos, v[off++]);
2088 pos += 8;
2089 }
2090 } else {
2091 dout.writeLong(v[off++]);
2092 }
2093 }
2094 }
2095
2096 void writeDoubles(double[] v, int off, int len) throws IOException {
2097 int limit = MAX_BLOCK_SIZE - 8;
2098 int endoff = off + len;
2099 while (off < endoff) {
2100 if (pos <= limit) {
2101 int avail = (MAX_BLOCK_SIZE - pos) >> 3;
2102 int chunklen = Math.min(endoff - off, avail);
2103 doublesToBytes(v, off, buf, pos, chunklen);
2104 off += chunklen;
2105 pos += chunklen << 3;
2106 } else {
2107 dout.writeDouble(v[off++]);
2108 }
2109 }
2110 }
2111
2112
2113
2114
2115 long getUTFLength(String s) {
2116 int len = s.length();
2117 long utflen = 0;
2118 for (int off = 0; off < len; ) {
2119 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2120 s.getChars(off, off + csize, cbuf, 0);
2121 for (int cpos = 0; cpos < csize; cpos++) {
2122 char c = cbuf[cpos];
2123 if (c >= 0x0001 && c <= 0x007F) {
2124 utflen++;
2125 } else if (c > 0x07FF) {
2126 utflen += 3;
2127 } else {
2128 utflen += 2;
2129 }
2130 }
2131 off += csize;
2132 }
2133 return utflen;
2134 }
2135
2136
2137
2138
2139
2140
2141
2142 void writeUTF(String s, long utflen) throws IOException {
2143 if (utflen > 0xFFFFL) {
2144 throw new UTFDataFormatException();
2145 }
2146 writeShort((int) utflen);
2147 if (utflen == (long) s.length()) {
2148 writeBytes(s);
2149 } else {
2150 writeUTFBody(s);
2151 }
2152 }
2153
2154
2155
2156
2157
2158
2159 void writeLongUTF(String s) throws IOException {
2160 writeLongUTF(s, getUTFLength(s));
2161 }
2162
2163
2164
2165
2166
2167 void writeLongUTF(String s, long utflen) throws IOException {
2168 writeLong(utflen);
2169 if (utflen == (long) s.length()) {
2170 writeBytes(s);
2171 } else {
2172 writeUTFBody(s);
2173 }
2174 }
2175
2176
2177
2178
2179
2180 private void writeUTFBody(String s) throws IOException {
2181 int limit = MAX_BLOCK_SIZE - 3;
2182 int len = s.length();
2183 for (int off = 0; off < len; ) {
2184 int csize = Math.min(len - off, CHAR_BUF_SIZE);
2185 s.getChars(off, off + csize, cbuf, 0);
2186 for (int cpos = 0; cpos < csize; cpos++) {
2187 char c = cbuf[cpos];
2188 if (pos <= limit) {
2189 if (c <= 0x007F && c != 0) {
2190 buf[pos++] = (byte) c;
2191 } else if (c > 0x07FF) {
2192 buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
2193 buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
2194 buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
2195 pos += 3;
2196 } else {
2197 buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
2198 buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
2199 pos += 2;
2200 }
2201 } else {
2202 if (c <= 0x007F && c != 0) {
2203 write(c);
2204 } else if (c > 0x07FF) {
2205 write(0xE0 | ((c >> 12) & 0x0F));
2206 write(0x80 | ((c >> 6) & 0x3F));
2207 write(0x80 | ((c >> 0) & 0x3F));
2208 } else {
2209 write(0xC0 | ((c >> 6) & 0x1F));
2210 write(0x80 | ((c >> 0) & 0x3F));
2211 }
2212 }
2213 }
2214 off += csize;
2215 }
2216 }
2217 }
2218
2219
2220
2221
2222
2223 private static class HandleTable {
2224
2225
2226 private int size;
2227
2228 private int threshold;
2229
2230 private final float loadFactor;
2231
2232 private int[] spine;
2233
2234 private int[] next;
2235
2236 private Object[] objs;
2237
2238
2239
2240
2241 HandleTable(int initialCapacity, float loadFactor) {
2242 this.loadFactor = loadFactor;
2243 spine = new int[initialCapacity];
2244 next = new int[initialCapacity];
2245 objs = new Object[initialCapacity];
2246 threshold = (int) (initialCapacity * loadFactor);
2247 clear();
2248 }
2249
2250
2251
2252
2253
2254 int assign(Object obj) {
2255 if (size >= next.length) {
2256 growEntries();
2257 }
2258 if (size >= threshold) {
2259 growSpine();
2260 }
2261 insert(obj, size);
2262 return size++;
2263 }
2264
2265
2266
2267
2268
2269 int lookup(Object obj) {
2270 if (size == 0) {
2271 return -1;
2272 }
2273 int index = hash(obj) % spine.length;
2274 for (int i = spine[index]; i >= 0; i = next[i]) {
2275 if (objs[i] == obj) {
2276 return i;
2277 }
2278 }
2279 return -1;
2280 }
2281
2282
2283
2284
2285 void clear() {
2286 Arrays.fill(spine, -1);
2287 Arrays.fill(objs, 0, size, null);
2288 size = 0;
2289 }
2290
2291
2292
2293
2294 int size() {
2295 return size;
2296 }
2297
2298
2299
2300
2301
2302 private void insert(Object obj, int handle) {
2303 int index = hash(obj) % spine.length;
2304 objs[handle] = obj;
2305 next[handle] = spine[index];
2306 spine[index] = handle;
2307 }
2308
2309
2310
2311
2312
2313 private void growSpine() {
2314 spine = new int[(spine.length << 1) + 1];
2315 threshold = (int) (spine.length * loadFactor);
2316 Arrays.fill(spine, -1);
2317 for (int i = 0; i < size; i++) {
2318 insert(objs[i], i);
2319 }
2320 }
2321
2322
2323
2324
2325 private void growEntries() {
2326 int newLength = (next.length << 1) + 1;
2327 int[] newNext = new int[newLength];
2328 System.arraycopy(next, 0, newNext, 0, size);
2329 next = newNext;
2330
2331 Object[] newObjs = new Object[newLength];
2332 System.arraycopy(objs, 0, newObjs, 0, size);
2333 objs = newObjs;
2334 }
2335
2336
2337
2338
2339 private int hash(Object obj) {
2340 return System.identityHashCode(obj) & 0x7FFFFFFF;
2341 }
2342 }
2343
2344
2345
2346
2347
2348 private static class ReplaceTable {
2349
2350
2351 private final HandleTable htab;
2352
2353 private Object[] reps;
2354
2355
2356
2357
2358 ReplaceTable(int initialCapacity, float loadFactor) {
2359 htab = new HandleTable(initialCapacity, loadFactor);
2360 reps = new Object[initialCapacity];
2361 }
2362
2363
2364
2365
2366 void assign(Object obj, Object rep) {
2367 int index = htab.assign(obj);
2368 while (index >= reps.length) {
2369 grow();
2370 }
2371 reps[index] = rep;
2372 }
2373
2374
2375
2376
2377
2378 Object lookup(Object obj) {
2379 int index = htab.lookup(obj);
2380 return (index >= 0) ? reps[index] : obj;
2381 }
2382
2383
2384
2385
2386 void clear() {
2387 Arrays.fill(reps, 0, htab.size(), null);
2388 htab.clear();
2389 }
2390
2391
2392
2393
2394 int size() {
2395 return htab.size();
2396 }
2397
2398
2399
2400
2401 private void grow() {
2402 Object[] newReps = new Object[(reps.length << 1) + 1];
2403 System.arraycopy(reps, 0, newReps, 0, reps.length);
2404 reps = newReps;
2405 }
2406 }
2407
2408
2409
2410
2411
2412 private static class DebugTraceInfoStack {
2413 private final List<String> stack;
2414
2415 DebugTraceInfoStack() {
2416 stack = new ArrayList<>();
2417 }
2418
2419
2420
2421
2422 void clear() {
2423 stack.clear();
2424 }
2425
2426
2427
2428
2429 void pop() {
2430 stack.remove(stack.size()-1);
2431 }
2432
2433
2434
2435
2436 void push(String entry) {
2437 stack.add("\t- " + entry);
2438 }
2439
2440
2441
2442
2443 public String toString() {
2444 StringBuilder buffer = new StringBuilder();
2445 if (!stack.isEmpty()) {
2446 for(int i = stack.size(); i > 0; i-- ) {
2447 buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : ""));
2448 }
2449 }
2450 return buffer.toString();
2451 }
2452 }
2453
2454 }